package com.eazy.lksy.web.core.dao;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import com.eazy.lksy.web.view.PageList;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;

import com.eazy.lksy.web.model.User;

@SuppressWarnings("deprecation")
public abstract class BaseDao {

	@Autowired
	protected JdbcTemplate dao;


	public JdbcTemplate getDao() {
		return dao;
	}
	
	public DB getDB() {
		return new DB();
	}


	/**
	 * 查询分页（MySQL数据库）
	 * @param sql     终执行查询的语句
	 * @param params  填充sql语句中的问号占位符数
	 * @param page    想要第几页的数据
	 * @param pagerow 每页显示多少条数
	 * @param cla     要封装成的实体元类型
	 * @return        pageList对象
	 */
	public PageList queryByPageForMySQL(String sql, Object[] params, int page, int pagerow,Class cla) {
		String rowsql="select count(*) from ("+sql+") gmtxtabs_";   //查询总行数sql
		int pages = 0;   //总页数
		int rows=(Integer)queryOneColumnForSigetonRow(rowsql, params, Integer.class);  //查询总行数
		//判断页数,如果是页大小的整数倍就为rows/pageRow如果不是整数倍就为rows/pageRow+1
		if (rows % pagerow == 0) {
			pages = rows / pagerow;
		} else {
			pages = rows / pagerow + 1;
		}
		//查询第page页的数据sql语句
		if(page<=1){
			sql+=" limit 0,"+pagerow;
		}else{
			sql+=" limit "+((page-1)*pagerow)+","+pagerow;
		}
		//查询第page页数据
		List list=null;
		if(cla!=null){
			list=queryForObjectList(sql, params, cla);
		}else{
			list=queryForMaps(sql, params);
		}

		//返回分页格式数据
		PageList pl =new PageList();
		pl.setRecordsFiltered(pages);  //设置总页数
		pl.setData(list);   //设置当前页数据
		pl.setRecordsTotal(pages);    //设置总记录数
		return pl;
	}

	/**
	 * 只查询一列数据类型对象。用于只有一行查询结果的数据
	 * @param sql
	 * @param params
	 * @param cla Integer.class,Float.class,Double.Class,Long.class,Boolean.class,Char.class,Byte.class,Short.class
	 * @return
	 */
	public Object queryOneColumnForSigetonRow(String sql,Object[] params,Class cla){
		Object result=null;
		try{
			if(params==null||params.length>0){
				result=dao.queryForObject(sql,params,cla);
			}else{
				result=dao.queryForObject(sql,cla);
			}
		}catch(Exception ex){
			ex.printStackTrace();
		}
		return result;
	}

	/**
	 * 查询返回实体对象集合
	 * @param sql    sql语句
	 * @param params 填充sql问号占位符数
	 * @param cla    实体对象类型
	 * @return
	 */
	public List queryForObjectList(String sql,Object[] params,final Class cla){
		ConvertUtils.register(new Converter() {
			@Override
			public Object convert(Class arg0, Object value) {
				if(value != null &&!"".equals(value.toString())){
					String v=value.toString();
					SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
					try {
						return	sdf.parse(v);
					} catch (ParseException e) {
						e.printStackTrace();
					}
				}
				return null;
			}
		}, Date.class);
		final List list=new ArrayList();
		try{
			dao.query(sql, params, new RowCallbackHandler(){
				public void processRow(ResultSet rs) {
					try{
						List<String> columnNames=new ArrayList<String>();
						ResultSetMetaData meta=rs.getMetaData();
						int num=meta.getColumnCount();
						for(int i=0;i<num;i++){
							columnNames.add(ToCamelUtilByString.changeByStr(meta.getColumnLabel(i+1).toLowerCase().trim()));
						}
						Method[] methods=cla.getMethods();
						List<String> fields=new ArrayList<String>();
						for(int i=0;i<methods.length;i++){
							if(methods[i].getName().trim().startsWith("set")){
								String f=methods[i].getName().trim().substring(3);
								f=(f.charAt(0)+"").toLowerCase().trim()+f.substring(1);
								fields.add(f);
							}
						}
						do{
							Object obj=null;
							try{
								obj=cla.getConstructor().newInstance();
							}catch(Exception ex){
								ex.printStackTrace();
							}
							for(int i=0;i<num;i++){
								Object objval=rs.getObject(i+1);
								for(int n=0;n<fields.size();n++){
									String fieldName=fields.get(n).trim();
									if(columnNames.get(i).equals(fieldName.trim())){
										BeanUtils.copyProperty(obj, fieldName, objval);
										break;
									}
								}
							}
							list.add(obj);
						}while(rs.next());
					}catch(Exception ex){
						ex.printStackTrace();
					}
				}
			});
		}catch(Exception ex){ex.printStackTrace();}
		if(list.size()<=0){
			return null;
		}
		return list;
	}
	static class ToCamelUtilByString {
		/**
		 * 将下划线命名转换驼峰式命名
		 * 0. 先将字符串以下划线字符进行分割
		 * 1. 从第1个下标开始将字符串的首字母转换成大写
		 * 2. 拼接所有字符串
		 * 3. 返回新的字符串
		 *
		 * @return 新的字段名称
		 */
		public static String changeByStr(String name) {
			StringBuilder result = new StringBuilder();
			// 快速检查
			if (name == null || name.isEmpty()) {
				// 没必要转换
				return "";
			} else if (!name.contains("_")) {
				// 不含下划线，仅将首字母小写
				return name.substring(0, 1).toLowerCase() + name.substring(1);
			}
			// 用下划线将原始字符串分割
			String camels[] = name.split("_");
			for (String camel : camels) {
				// 跳过原始字符串中开头、结尾的下换线或双重下划线
				if (camel.isEmpty()) {
					continue;
				}
				// 处理真正的驼峰片段
				if (result.length() == 0) {
					// 第一个驼峰片段，全部字母都小写
					result.append(camel.toLowerCase());
				} else {
					// 其他的驼峰片段，首字母大写
					result.append(camel.substring(0, 1).toUpperCase());
					result.append(camel.substring(1).toLowerCase());
				}
			}
			return result.toString();
		}
	}

	/**
	 * 查询返回List<Map<String,Object>>格式数据,每一个Map代表一行数据，列名为key
	 * @param sql  sql语句
	 * @param params 填充问号占位符数
	 * @return
	 */
	public List<Map<String,Object>> queryForMaps(String sql,Object[] params){
		try{
			if(params!=null&&params.length>0){
				return dao.queryForList(sql, params);
			}
			return dao.queryForList(sql);
		}catch(Exception ex){
			ex.printStackTrace();
		}
		return null;
	}



	public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper) {
		return new DB().queryForObject(sql, args,rowMapper);
	}

	public <T> Map<String, Object> queryForMap(String sql, Object... args) {
		return new DB().queryForMap(sql,args);
	}

	class DB {
		protected PreparedStatementSetter newArgPreparedStatementSetter(Object[] args) {
			return new ArgumentPreparedStatementSetter(args);
		}

		public <T> Map<String, Object> queryForMap(String sql, Object... args) {
			return queryForObject(sql, args, getColumnMapRowMapper());
		}

		public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
			List<T> results = query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));
			return requiredSingleResult(results);
		}

		public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
			return query(sql, newArgPreparedStatementSetter(args), rse);
		}

		public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse)
				throws DataAccessException {
			return getDao().query(sql, pss, rse);
		}

		protected RowMapper<Map<String, Object>> getColumnMapRowMapper() {
			return new ColumnMapRowMapper();
		}

		public <T> T requiredSingleResult(Collection<T> results) throws IncorrectResultSizeDataAccessException {
			int size = (results != null ? results.size() : 0);
			if (size == 0) {
				return null;
			}
			if (results.size() > 1) {
				throw new IncorrectResultSizeDataAccessException(1, size);
			}
			return results.iterator().next();
		}
	}

}
